好的命名讓你上天堂,壞的命名讓你住套房。
誰都寫得出機器看的懂的程式碼,但好的程式碼是讓人可以輕易看懂的。
這篇文章以Clean Code這本書中,提到的Meaningful Names應該要注意哪些地方來供各位當個參考。
在這篇文章開始之前,要先提出一個重要的觀念,雖然好的Naming很重要,但還有一個rule比這重要,就是一致性。如果今天是針對已經存在的系統要附加新的功能或是修改舊的程式,那麼『一致性』要比新的Naming rule重要!在導入新的coding style時,一定要謹慎的審視是否會導致現有系統在閱讀上的障礙,導致後續團隊開發時無所適從。
[如何提升系統品質]系列文章連結
1.Use Intention-Revealing Names:透過命名就能淺而易見其意圖
如果一個命名,還需要註解來解釋它,就代表他還不夠清楚表示意思。
(1)不好的例子:
int d; // elapsed time in days
(2)好的例子:
int elapsedTimeInDays;
int daysSinceCreation;
int daysSinceModification;
int fileAgeInDays;
2.Avoid Disinformation:避免誤導
(1)不要使用特殊或多重意義的縮寫
(2)避免使用具有特殊意義的關鍵字命名
例如:accountList,因為List是關鍵字,所以可以取成accounts或accountGroup。
(3)避免兩個命名太長且太相像
您能看得出來這兩個的差異嗎?
XYZControllerForEfficientHandlingOfStrings
XYZControllerForEfficientStorageOfStrings
應該將贅字移除。
(4)代表同樣意思、同一件事、同一個東西時,命名應該一致(可透過glossary來統一)
(5)避免1與L的差異,0與O的差異
例如:
int a = l;
if ( O == l )
a = O1;
else
l = 01;
3.Make Meaningful Distinctions
獨自開發時容易因為一時的方便,只為了建置或開發方便,而隨手使用了不具意義或暫時的命名,往往之後帶來相當多潛在的問題。
(1)避免Number-series naming
例如:
public static void copyChars(char a1[], char a2[]) {
for (int i = 0; i < a1.length; i++) {
a2[i] = a1[i];
}
}
(2)避免用不同字眼代表同一件事,例如info與data,或是a, an, the的差異
(3)避免贅字
例如以下的程式碼,會造成閱讀的人產生疑惑,這三個function有什麼差異:
getActiveAccount();
getActiveAccounts();
getActiveAccountInfo();
4.Use Pronounceable Names,使用可以發音的Name,可以幫助溝通,溝通時比較不會彆扭,不會顯得愚蠢。
(1)無法發音的Naming
class DtaRcrd102 {
private Date genymdhms;
private Date modymdhms;
private final String pszqint = "102";
};
(2)轉換成可以發音的Naming
class Customer {
private Date generationTimestamp;
private Date modificationTimestamp;;
private final String recordId = "102";
/* ... */
};
5.Use Searchable Names,當需要尋找時,找不到真的是欲哭無淚。
(1)避免用數字與單一字母命名,可改採用constant或Enum賦予意義。單一字母的命名,最多只允許在很短的迴圈或method中使用。
(2)longer names比shorter names好,至少搜尋容易定位
(3)很難搜尋的code:
for (int j=0; j<34; j++) {
s += (t[j]*4)/5;
}
(4)轉換後的code:
int realDaysPerIdealDay = 4;
const int WORK_DAYS_PER_WEEK = 5;
int sum = 0;
for (int j=0; j < NUMBER_OF_TASKS; j++) {
int realTaskDays = taskEstimate[j] * realDaysPerIdealDay;
int realTaskWeeks = (realdays / WORK_DAYS_PER_WEEK);
sum += realTaskWeeks;
}
6.Avoid Encodings,避免自行定義特殊的編碼命名規則,會增加維護上的困難跟training成本
(1)編碼命名方式,會導致正常人都無法瞭解該命名意義:
例如class名稱命成:RGB001_256A
7.Hungarian Notation,匈牙利命名法有其時代背景的需求,但現在的IDE工具進步許多,理應避免這樣的避免方式。
(1)由來
Fortran開始使用first letter for the type,也就是匈牙利命名法
在C的時代,compiler不會幫忙檢查 type,所以HN是有意義的
(2)class跟function只負責單一功能,要能一眼看出來每一個變數的意義,加上型別prefix只是贅字
(3)不再需要type encoding ,加上type反而導致未來修改型別時,需要改更多的命名,否則將導致bug
例子
PhoneNumber phoneString;
// name not changed when type changed!
8.Member Prefixes,同上,IDE工具可以讓我們快速找到該變數的定義,不需要再透過前置詞來表示該變數是區域、全域或屬性
(1)不好的例子:
(2)轉換後的例子:
9.類別名稱使用單數名詞,function名稱使用動詞。
10.Don't Be Cute,不要在Naming上搞笑,可能導致只有自己懂笑點,而別人搞不懂這個東西是什麼。盡量用白話、常見的term命名,不要用文言文,或俚語。
11.Don't Pun,不要用雙關語。一語雙關,會導致讓讀者有猜測的空間,或需要玩猜猜看。
12.Don't Add Gratuitous Context,每個東西命名若都加上application或class的prefix,反而造成每個term都有,那就多餘了。最常見在DB Table的欄位命名,或是類別的屬性命名。
結論:
不要害怕rename,現在的現在的IDE重構工具都相當方便使用,持續使用refactoring tool 改善命名,只需要花一點小時間就可以省下以後一長段時間。當然,還是有個重要的前提:『重新命名之前,要確認是否已經公開給外界使用,若已經有外部服務相依於此命名,那麼不要輕易的更動這個命名』
Question:
您能找出下面這段程式碼,有哪些問題嗎?
我其實搞不太懂你們整天「討論」前後人程式維護難易度是要做什麼??
他又不是你的爸爸媽媽,有什麼義務寫到讓你能改?
而且a1的命名只是增加維護難度而已
跟你一串名字比起來,省了快一半的記憶體。
臉書、谷歌、矽谷他們的程式,大部份也都給他「亂碼」化了。
亂碼後的變數名稱也都沒超過10個字元。
事實擺明
1.我們沒有義務讓別人能輕輕鬆鬆懂我們的程式
2.如有需要,我們可以使其複雜化,在沒有增加伺服器負擔的情況下。
3.命名都要亂碼化,除非給自已看,不然沒意義。
給外部的可以訪照現實
建立「機場」、「港口」就好。
他們的機能就是檢測出入口、資料的核對與加密。
而且,我看了你不少串的這系列文章。
我可以跟你講
你的文章也需要重構。
沒有起承轉合,也沒有H1、H2、H3做好標題的分類「大、中、小」。
就算這網站不支援,你一樣可以用縮排達到目地。
你用這麼不適閱讀的方式,來講解程式重構,給看文的人感受其說服力真的有待加強。